﻿using System;
using System.Collections.Generic;
using System.IO;
using Autodesk.Revit.DB;
using YJKRevitKernel.ElementSearchUtility.LinkDocumentSuite;
using YJKGeometryFuncs;
using YJKPatternSign.StairsRoomSection.DataDefine;
using YJKPatternSign.StairsRoomSection.Manager;

namespace YJKPatternSign.StairsRoomSection.Kit
{
	internal class CommonFun
	{
		public static bool SureElementInPlanLine(Element element, Line line, XYZ ViewDir)
		{
			List<Curve> list = new List<Curve>();
			new List<Curve>();
			XYZ viewOrgin = (line.GetEndPoint(0) + line.GetEndPoint(1)) / 2.0;
			XYZ xyz = line.Direction.Normalize().CrossProduct(ViewDir);
			CommonFun.GetOutSide(ref list, element, viewOrgin, xyz.Normalize());
			IntersectionResultArray intersectionResultArray = null;
			foreach (Curve curve in list)
			{
				line.Intersect(curve, out intersectionResultArray);
				if (intersectionResultArray != null)
				{
					return true;
				}
			}
			return (element is Floor || element is Wall || element is RoofBase) && Geometry.PointInPloygon(list, line.GetEndPoint(0)) != -1;
		}

		public static void GetOutSide(ref List<Curve> curveProj, Element element, XYZ viewOrgin, XYZ viewDir)
		{
			List<Curve> curveOrg = new List<Curve>();
			CommonFun.FindCurveInNormal(ref curveOrg, viewDir, element);
			CommonFun.ProjectLinesToPlan(ref curveProj, curveOrg, viewOrgin, viewDir);
		}

		public static void ProjectLinesToPlan(ref List<Curve> curveProj, List<Curve> curveOrg, XYZ viewOrgin, XYZ viewDir)
		{
			for (int i = 0; i < curveOrg.Count; i++)
			{
				Curve curve = curveOrg[i];
				XYZ endPoint = curve.GetEndPoint(0);
				double num = (viewOrgin - endPoint).DotProduct(viewDir);
				Transform transform = Transform.CreateTranslation(viewDir * num);
				curve = curve.CreateTransformed(transform);
				curveProj.Add(curve);
			}
		}

		public static bool FindFaceInNormal(ref List<Face> faceInNormal, XYZ normalFace, Element elem)
		{
			List<Solid> list = new List<Solid>();
			CommonFun.GetSolidFromABeam(list, elem);
			for (int i = 0; i < list.Count; i++)
			{
				Solid solid = list[i];
				for (int j = 0; j < solid.Faces.Size; j++)
				{
					Face face = solid.Faces.get_Item(j);
					BoundingBoxUV boundingBox = face.GetBoundingBox();
					UV uv = (boundingBox.Min + boundingBox.Max) / 2.0;
					if (Geometry.LessThan(solid.Faces.get_Item(j).ComputeNormal(uv).Normalize().AngleTo(normalFace), Math.PI*.5))
					{
						faceInNormal.Add(face);
					}
				}
			}
			return true;
		}

		public static bool FindCurveInNormal(ref List<Curve> curveInNormal, XYZ normalFace, Element elem)
		{
			List<Face> list = new List<Face>();
			CommonFun.FindFaceInNormal(ref list, normalFace, elem);
			List<Curve> list2 = new List<Curve>();
			for (int i = 0; i < list.Count; i++)
			{
				EdgeArrayArray edgeLoops = list[i].EdgeLoops;
				for (int j = 0; j < edgeLoops.Size; j++)
				{
					for (int k = 0; k < edgeLoops.get_Item(j).Size; k++)
					{
						Curve item = edgeLoops.get_Item(j).get_Item(k).AsCurve();
						list2.Add(item);
					}
				}
			}
			curveInNormal = list2;
			return true;
		}

		public static void GetSolidFromABeam(List<Solid> solids, Element elem)
		{
			GeometryElement geomElem = elem.get_Geometry(new Options
			{
				ComputeReferences = true
			});
			CurveArray curveArray = new CurveArray();
			CommonFun.AddCurvesAndSolids(geomElem, ref curveArray, ref solids);
		}

		public static Solid CutWithHalfSpace(Solid solid, SectionViewData viewSectionInfo, Plane planeCut, bool isSelfPlan)
		{
			XYZ xyz = viewSectionInfo.m_SecLine.Direction.Normalize();
			XYZ viewDir = viewSectionInfo.m_viewDir;
			XYZ xyz2 = viewSectionInfo.m_SecLine.GetEndPoint(0) - 1000.0 * xyz;
			XYZ xyz3 = viewSectionInfo.m_SecLine.GetEndPoint(1) + 1000.0 * xyz;
			double secHeith = viewSectionInfo.m_SecHeith;
			IList<CurveLoop> list = new List<CurveLoop>();
			IList<Curve> list2 = new List<Curve>();
			new CurveLoop();
			BoundingBoxXYZ boundingBox = solid.GetBoundingBox();
			double num = boundingBox.Max.DistanceTo(boundingBox.Min);
			XYZ xyz4 = xyz.CrossProduct(viewDir).Normalize();
			XYZ xyz5 = xyz2 + xyz4 * secHeith;
			XYZ xyz6 = xyz3 + xyz4 * secHeith;
			XYZ xyz7 = xyz3 - xyz4 * secHeith;
			XYZ xyz8 = xyz2 - xyz4 * secHeith;
			if (!isSelfPlan)
			{
				XYZ xvec = planeCut.XVec;
				XYZ yvec = planeCut.YVec;
				double num2 = 1000.0;
				xyz5 = planeCut.Origin + num * num2 * planeCut.XVec + num * num2 * planeCut.YVec;
				xyz6 = planeCut.Origin + num * num2 * planeCut.XVec - num * num2 * planeCut.YVec;
				xyz7 = planeCut.Origin - num * num2 * planeCut.XVec - num * num2 * planeCut.YVec;
				xyz8 = planeCut.Origin - num * num2 * planeCut.XVec + num * num2 * planeCut.YVec;
			}
			Curve item = Line.CreateBound(xyz5, xyz6);
			list2.Add(item);
			item = Line.CreateBound(xyz6, xyz7);
			list2.Add(item);
			item = Line.CreateBound(xyz7, xyz8);
			list2.Add(item);
			item = Line.CreateBound(xyz8, xyz5);
			list2.Add(item);
			CurveLoop item2 = CurveLoop.Create(list2);
			list.Add(item2);
			Solid solid2 = GeometryCreationUtilities.CreateExtrusionGeometry(list, -planeCut.Normal, num);
			Solid result;
			try
			{
				result = BooleanOperationsUtils.ExecuteBooleanOperation(solid, solid2, (Autodesk.Revit.DB.BooleanOperationsType)1);
			}
			catch (Exception)
			{
				result = null;
			}
			return result;
		}

		private static void AddCurvesAndSolids(GeometryElement geomElem, ref CurveArray curves, ref List<Solid> solids)
		{
			foreach (GeometryObject geometryObject in geomElem)
			{
				Curve curve = geometryObject as Curve;
				if (null != curve)
				{
					curves.Append(curve);
				}
				else
				{
					Solid solid = geometryObject as Solid;
					if (null != solid)
					{
						solids.Add(solid);
					}
					else
					{
						GeometryInstance geometryInstance = geometryObject as GeometryInstance;
						if (null != geometryInstance)
						{
							CommonFun.AddCurvesAndSolids(geometryInstance.GetInstanceGeometry(), ref curves, ref solids);
						}
					}
				}
			}
		}

		public static List<Curve> CutElement(Element element, SectionViewData viewSectionInfo, Plane plane)
		{
			List<Curve> list = new List<Curve>();
			List<Solid> list2 = new List<Solid>();
			CommonFun.GetSolidFromABeam(list2, element);
			for (int i = 0; i < list2.Count; i++)
			{
				Solid solid = list2[i];
				if (solid.Edges.Size != 0 && solid.Faces.Size != 0)
				{
					List<Curve> collection = CommonFun.CutSolid(solid, viewSectionInfo, plane);
					list.AddRange(collection);
				}
			}
			return list;
		}

		private static List<Curve> CutSolid(Solid solid, SectionViewData viewSectionInfo, Plane plane)
		{
			List<Curve> list = new List<Curve>();
			solid = CommonFun.CutWithHalfSpace(solid, viewSectionInfo, plane, true);
			if (solid == null)
			{
				return list;
			}
			for (int i = 0; i < solid.Faces.Size; i++)
			{
				Face face = solid.Faces.get_Item(i);
				BoundingBoxUV boundingBox = face.GetBoundingBox();
				UV uv = (boundingBox.Min + boundingBox.Max) / 2.0;
				if (Geometry.IsEqual((solid.Faces.get_Item(i).Evaluate(uv) - plane.Origin).Normalize().Normalize().DotProduct(plane.Normal), 0.0))
				{
					foreach (object obj in face.EdgeLoops)
					{
						foreach (object obj2 in ((EdgeArray)obj))
						{
							Edge edge = (Edge)obj2;
							list.Add(edge.AsCurve());
						}
					}
				}
			}
			return list;
		}

		public static List<Curve> TranCurve(List<Curve> curves, XYZ vecTran)
		{
			List<Curve> list = new List<Curve>();
			for (int i = 0; i < curves.Count; i++)
			{
				Transform transform = Transform.CreateTranslation(vecTran);
				Curve item = curves[i].CreateTransformed(transform);
				list.Add(item);
			}
			return list;
		}

		public static List<Curve> TranCurve(List<Curve> curves, Transform mat)
		{
			List<Curve> list = new List<Curve>();
			for (int i = 0; i < curves.Count; i++)
			{
				Curve item = curves[i].CreateTransformed(mat);
				list.Add(item);
			}
			return list;
		}

		public static Document getLinkDocument(BaseLinkDocumentResultBean elemObj)
		{
			DocumentSet documents = SectionStairsRoomManager.g_application.Documents;
			if (elemObj.LinkeInstanceId == -1)
			{
				return elemObj.UseElement.Document;
			}
			Document result;
			try
			{
				string pathName = elemObj.UseElement.Document.PathName;
				string text = pathName.Insert(pathName.Length - 4, "TMP");
				foreach (object obj in documents)
				{
					Document document = obj as Document;
					if (document.PathName.Equals(text))
					{
						return document;
					}
				}
				File.Copy(pathName, text, true);
				result = SectionStairsRoomManager.g_application.OpenDocumentFile(text);
			}
			catch (Exception)
			{
				result = null;
			}
			return result;
		}

		public static void TransformViewData(BaseLinkDocumentResultBean elemObj, SectionViewData ViewInfoRay, out SectionViewData ViewInfo)
		{
			Transform totalTransform = elemObj.GetTotalTransform();
			Line line = ViewInfoRay.m_SecLine.CreateTransformed(totalTransform.Inverse) as Line;
            //(line.GetEndPoint(0) + line.GetEndPoint(1)) / 2.0;
			XYZ xyz = ViewInfoRay.m_viewDir;
			xyz = totalTransform.Inverse.OfVector(xyz);
			ViewInfo = ViewInfoRay.clone();
			ViewInfo.m_SecLine = line;
			ViewInfo.m_viewDir = xyz;
		}

		public static bool CopyElementsFromLinkDocToCurrentDoc(Autodesk.Revit.DB.Document Curdoc, List<BaseLinkDocumentResultBean> lstelemObj, ref List<ElementId> lstNewId)
		{
			List<ElementId> list = new List<ElementId>();
			Document document = lstelemObj[0].UseElement.Document;
			Transform totalTransform = lstelemObj[0].GetTotalTransform();
			foreach (BaseLinkDocumentResultBean baseLinkDocumentResultBean in lstelemObj)
			{
				Element useElement = baseLinkDocumentResultBean.UseElement;
				list.Add(useElement.Id);
			}
			try
			{
				lstNewId = (ElementTransformUtils.CopyElements(document, list, Curdoc, totalTransform, new CopyPasteOptions()) as List<ElementId>);
			}
			catch (Exception)
			{
				return false;
			}
			return true;
		}
	}
}
